home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / kernel / clock.c next >
C/C++ Source or Header  |  1990-07-23  |  14KB  |  393 lines

  1. /* This file contains the code and data for the clock task.  The clock task
  2.  * has a single entry point, clock_task().  It accepts four message types:
  3.  *
  4.  *   HARD_INT:    a clock interrupt has occurred
  5.  *   GET_TIME:    a process wants the real time
  6.  *   SET_TIME:    a process wants to set the real time
  7.  *   SET_ALARM:   a process wants to be alerted after a specified interval
  8.  *
  9.  * The input message is format m6.  The parameters are as follows:
  10.  *
  11.  *     m_type    CLOCK_PROC   FUNC    NEW_TIME
  12.  * ---------------------------------------------
  13.  * | SET_ALARM  | proc_nr  |f to call|  delta  |
  14.  * |------------+----------+---------+---------|
  15.  * | HARD_INT   |          |         |         |
  16.  * |------------+----------+---------+---------|
  17.  * | GET_TIME   |          |         |         |
  18.  * |------------+----------+---------+---------|
  19.  * | SET_TIME   |          |         | newtime |
  20.  * ---------------------------------------------
  21.  *
  22.  * When an alarm goes off, if the caller is a user process, a SIGALRM signal
  23.  * is sent to it.  If it is a task, a function specified by the caller will
  24.  * be invoked.  This function may, for example, send a message, but only if
  25.  * it is certain that the task will be blocked when the timer goes off.
  26.  */
  27.  
  28. #include "kernel.h"
  29. #include <signal.h>
  30. #include <minix/callnr.h>
  31. #include <minix/com.h>
  32. #include "proc.h"
  33.  
  34. /* Constant definitions. */
  35. #define MILLISEC         100    /* how often to call the scheduler (msec) */
  36. #define SCHED_RATE (MILLISEC*HZ/1000)    /* number of ticks per schedule */
  37.  
  38. /* Clock parameters. */
  39. #if (CHIP == INTEL)
  40. #define COUNTER_FREQ (2*TIMER_FREQ)    /* counter frequency using sqare wave*/
  41. #define LATCH_COUNT     0x00    /* cc00xxxx, c = channel, x = any */
  42. #define SQUARE_WAVE     0x36    /* ccaammmb, a = access, m = mode, b = BCD */
  43.                 /*   11x11, 11 = LSB then MSB, x11 = sq wave */
  44. #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
  45. #define TIMER_FREQ   1193182L    /* clock frequency for timer in PC and AT */
  46. #endif
  47.  
  48. #if (CHIP == M68000)
  49. #define FLUSH_MASK      0x07    /* bit mask used for flushing RS232 input */
  50. #define TIMER_FREQ   2457600L    /* timer 3 input clock frequency */
  51. #endif
  52.  
  53. /* Clock task variables. */
  54. PRIVATE time_t boot_time;    /* time in seconds of system boot */
  55. PRIVATE time_t next_alarm;    /* probable time of next alarm */
  56. PRIVATE time_t pending_ticks;    /* ticks seen by low level only */
  57. PRIVATE time_t realtime;    /* real time clock */
  58. PRIVATE int sched_ticks = SCHED_RATE;    /* counter: when 0, call scheduler */
  59. PRIVATE struct proc *prev_ptr;    /* last user process run by clock task */
  60. PRIVATE message mc;        /* message buffer for both input and output */
  61. PRIVATE void (*watch_dog[NR_TASKS+1])();  /* watch_dog functions to call */
  62.  
  63. FORWARD void do_clocktick();
  64. FORWARD void do_get_time();
  65. FORWARD void do_set_time();
  66. FORWARD void do_setalarm();
  67. FORWARD void init_clock();
  68.  
  69. /*===========================================================================*
  70.  *                clock_task                     *
  71.  *===========================================================================*/
  72. PUBLIC void clock_task()
  73. {
  74. /* Main program of clock task.  It determines which of the 4 possible
  75.  * calls this is by looking at 'mc.m_type'.   Then it dispatches.
  76.  */
  77.  
  78.   int opcode;
  79.  
  80.   init_clock();            /* initialize clock task */
  81.  
  82.   /* Main loop of the clock task.  Get work, process it, sometimes reply. */
  83.   while (TRUE) {
  84.      receive(ANY, &mc);        /* go get a message */
  85.      opcode = mc.m_type;    /* extract the function code */
  86.  
  87.      lock();
  88.      realtime += pending_ticks;    /* transfer ticks from low level handler */
  89.      pending_ticks = 0;
  90.      unlock();
  91.  
  92.      switch (opcode) {
  93.     case SET_ALARM:     do_setalarm(&mc);    break;
  94.     case GET_TIME:     do_get_time();        break;
  95.     case SET_TIME:     do_set_time(&mc);    break;
  96.     case HARD_INT:   do_clocktick();    break;
  97.     default: panic("clock task got bad message", mc.m_type);
  98.      }
  99.  
  100.     /* Send reply, except for clock tick. */
  101.     mc.m_type = OK;
  102.     if (opcode != HARD_INT) send(mc.m_source, &mc);
  103.   }
  104. }
  105.  
  106.  
  107. /*===========================================================================*
  108.  *                do_setalarm                     *
  109.  *===========================================================================*/
  110. PRIVATE void do_setalarm(m_ptr)
  111. message *m_ptr;            /* pointer to request message */
  112. {
  113. /* A process wants an alarm signal or a task wants a given watch_dog function
  114.  * called after a specified interval.  Record the request and check to see
  115.  * it is the very next alarm needed.
  116.  */
  117.  
  118.   register struct proc *rp;
  119.   int proc_nr;            /* which process wants the alarm */
  120.   long delta_ticks;        /* in how many clock ticks does he want it? */
  121.   void (*function)();        /* function to call (tasks only) */
  122.  
  123.   /* Extract the parameters from the message. */
  124.   proc_nr = m_ptr->CLOCK_PROC_NR;    /* process to interrupt later */
  125.   delta_ticks = m_ptr->DELTA_TICKS;    /* how many ticks to wait */
  126.   function = m_ptr->FUNC_TO_CALL;    /* function to call (tasks only) */
  127.   rp = proc_addr(proc_nr);
  128.   mc.SECONDS_LEFT = (rp->p_alarm == 0L ? 0 : (rp->p_alarm - realtime)/HZ );
  129.   rp->p_alarm = (delta_ticks == 0L ? 0L : realtime + delta_ticks);
  130.   if (istaskp(rp)) watch_dog[-proc_nr] = function;
  131.  
  132.   /* Which alarm is next? */
  133.   next_alarm = MAX_P_LONG;
  134.   for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
  135.     if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
  136.  
  137. }
  138.  
  139.  
  140. /*===========================================================================*
  141.  *                do_get_time                     *
  142.  *===========================================================================*/
  143. PRIVATE void do_get_time()
  144. {
  145. /* Get and return the current clock time in ticks. */
  146.  
  147.   mc.m_type = REAL_TIME;    /* set message type for reply */
  148.   mc.NEW_TIME = boot_time + realtime/HZ;    /* current real time */
  149. }
  150.  
  151.  
  152. /*===========================================================================*
  153.  *                do_set_time                     *
  154.  *===========================================================================*/
  155. PRIVATE void do_set_time(m_ptr)
  156. message *m_ptr;            /* pointer to request message */
  157. {
  158. /* Set the real time clock.  Only the superuser can use this call. */
  159.  
  160.   boot_time = m_ptr->NEW_TIME - realtime/HZ;
  161. }
  162.  
  163.  
  164. /*===========================================================================*
  165.  *                do_clocktick                     *
  166.  *===========================================================================*/
  167. PRIVATE void do_clocktick()
  168. {
  169. /* This routine called on clock ticks when a lot of work needs to be done. */
  170.  
  171.   register struct proc *rp;
  172.   register int proc_nr;
  173.  
  174.   if (next_alarm <= realtime) {
  175.     /* An alarm may have gone off, but proc may have exited, so check. */
  176.     next_alarm = MAX_P_LONG;    /* start computing next alarm */
  177.     for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
  178.         if (rp->p_alarm != (time_t) 0) {
  179.             /* See if this alarm time has been reached. */
  180.             if (rp->p_alarm <= realtime) {
  181.                 /* A timer has gone off.  If it is a user proc,
  182.                  * send it a signal.  If it is a task, call the
  183.                  * function previously specified by the task.
  184.                  */
  185.                 if ( (proc_nr = proc_number(rp)) >= 0)
  186.                     cause_sig(proc_nr, SIGALRM);
  187.                 else
  188.                     (*watch_dog[-proc_nr])();
  189.                 rp->p_alarm = 0;
  190.             }
  191.  
  192.             /* Work on determining which alarm is next. */
  193.             if (rp->p_alarm != (time_t)0 && rp->p_alarm < next_alarm)
  194.                 next_alarm = rp->p_alarm;
  195.         }
  196.     }
  197.   }
  198.  
  199.   /* If a user process has been running too long, pick another one. */
  200.   if (--sched_ticks == 0) {
  201.     if (bill_ptr == prev_ptr) lock_sched();    /* process has run too long */
  202.     sched_ticks = SCHED_RATE;        /* reset quantum */
  203.     prev_ptr = bill_ptr;            /* new previous process */
  204.   }
  205. #if (CHIP == M68000)
  206.   if (rdy_head[SHADOW_Q]) unshadow(rdy_head[SHADOW_Q]);
  207. #endif
  208. }
  209.  
  210.  
  211. #if (CHIP == INTEL)
  212. /*===========================================================================*
  213.  *                init_clock                     *
  214.  *===========================================================================*/
  215. PRIVATE void init_clock()
  216. {
  217. /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
  218.  
  219.   out_byte(TIMER_MODE, SQUARE_WAVE);    /* set timer to run continuously */
  220.   out_byte(TIMER0, TIMER_COUNT);    /* load timer low byte */
  221.   out_byte(TIMER0, TIMER_COUNT >> 8);    /* load timer high byte */
  222.   enable_irq(CLOCK_IRQ);    /* ready for clock interrupts */
  223. }
  224.  
  225.  
  226.